Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add wait-change API endpoint and client function #63

Merged
merged 5 commits into from Aug 31, 2021

Conversation

benhoyt
Copy link
Contributor

@benhoyt benhoyt commented Aug 16, 2021

This adds an endpoint to the Pebble API to wait for a change to be ready, with an optional timeout. It's intended for use with the upcoming "exec" feature (spec and WIP PR). The LXD code has a similar feature, except changes are called "operations" in LXD, and there's a "wait operation" API endpoint.

This is particularly important for "pebble exec", so we can wait for the command to be finished without polling every short interval, and we can return a response immediately when the command finishes executing.

In future we could also use this new endpoint in the pebble start and pebble stop commands (and Python Operator Framework equivalents) to avoid polling there too.

Copy link
Member

@hpidcock hpidcock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just two selects that need fixing.

internal/daemon/api_changes.go Outdated Show resolved Hide resolved
internal/daemon/api_changes.go Show resolved Hide resolved
@benhoyt benhoyt requested a review from niemeyer August 16, 2021 04:25
Copy link
Contributor

@niemeyer niemeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good, thanks Ben. Just a few minor points:

// If non-zero, wait at most this long before returning the current change
// data. The timeout elapsing is not considered an error, so if a timeout
// is specified, the caller should check Change.Ready to determine whether
// the change is actually finished.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Timeout certainly sounds like an error, unless the operation did finish and there was a race condition. But otherwise, the intent of the operation of waiting for it to be finished did not succeed in intent, so an error seems appropriate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, Harry and I went back and forth on that and ended up that it shouldn't be an error, primarily because when Pebble returns an error it can't also return other data (the Change in this case), and I thought it might be useful to have the current state of the change at the time of the timeout.

However, on reflection it makes for a less error-prone API if it's just an error, and in the success case the change is always ready. If the caller really wants the current state of a change in the case of a timeout/error, they can always make an additional call to client.Change() to get the current status. However, it's unlikely you'll want to.

In any case, I've used HTTP status code 504 Gateway Timeout for this (along with a reasonable error message). It's not quite a perfect semantic match, but it seems close enough.

client/changes.go Outdated Show resolved Hide resolved
query.Set("timeout", opts.Timeout.String())
}

_, err := client.doSync("GET", "/v1/changes/"+id+"/wait", query, nil, nil, &chgd)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the timeout behavior of the underlying http library, and do we have to account for that and implement retries here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. I had observed it to be a very long timeout / no timeout in my manual testing, but just confirmed that now in the code -- we always create the http.Client with no Timeout specified, so no timeout applies here. Arguably that's bad practice, but we can follow up in a subsequent PR if we want to change that.

@benhoyt
Copy link
Contributor Author

benhoyt commented Aug 31, 2021

@niemeyer I've addressed your concerns -- mainly making the timeout an error and tweaking the doc comments. I'm going to go ahead and merge; we can always tweak later if necessary.

@benhoyt benhoyt merged commit 92ac541 into canonical:master Aug 31, 2021
@benhoyt benhoyt deleted the wait-change branch August 31, 2021 02:39
benhoyt added a commit to canonical/operator that referenced this pull request Sep 2, 2021
Corresponds to the new wait-change API endpoint in
canonical/pebble#63. This uses the new API if it's
present, otherwise falls back to the existing polling-every-100ms method.
benhoyt added a commit to benhoyt/juju that referenced this pull request Oct 1, 2021
More specifically, these PRs:

* canonical/pebble#59 Add GPLv3 license (to match source header and snapd)
* canonical/pebble#64 Avoid use of multipart.Part.FileName() to fix files API on Go 1.17
* canonical/pebble#63 Add wait-change API endpoint and client function
* canonical/pebble#65 Make Pebble "go vet" clean
* canonical/pebble#66 Remove a bunch of snapd references
* canonical/pebble#67 Add API section to README; add HACKING.md; remove Makefile
* canonical/pebble#60 Add Replan operation to restart changed services.
* canonical/pebble#61 One-shot commands (pebble exec)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants